// 注：这个文件被用于对“axios”进行二次封装（封装的目的是使用请求与响应拦截器）
import axios from "axios";
import { ElMessage } from "element-plus";
// 导入与用户信息相关的仓库↓
import useUserStore from "@/store/modules/user";
//第一步：通过axios对象上的create方法，根据一个配置对象（其中包含“基础路径”、“超时时间”等配置）来创建axios实例↓
let request = axios.create({
    baseURL: import.meta.env.VITE_APP_BASE_API, // 设置基础路径（根据环境变量）（开发环境下基础路径是“/api”）
    timeout: 5000 // 设置超时时间（毫秒）
})
// 第二步：向“axios实例对象”添加请求拦截器与响应拦截器↓
//请求拦截器（注：请求拦截器被触发时，被执行的回调函数会注入配置对象——“config”作为参数）
request.interceptors.request.use(config => {
    // 在此处获取与用户信息相关的仓库的实例对象（获取该对象的目的是：通过它来获取位于其内部的token，在登录成功后向服务器发送请求时把这个token作为“公共参数”传递给服务器）↓
    let userStore = useUserStore(); // 注：此处通过调用“useUserStore”函数，获取了与用户信息相关的仓库的实例对象（即“userStore”）
    console.log(userStore.token) // Admin Token
    // config.headers.token = "123456"; // 注：此处通过修改配置对象中的“headers”属性，向请求头中添加了一个名为“token”的字段（此处仅作演示用）
    console.log(config) // 注：此处打印出来的“config”对象是一个配置对象（它包含了请求的详细信息（如请求的URL、请求头信息等））（控制台中输出“{transitional: {…}, adapter: Array(3), transformRequest: Array(1), transformResponse: Array(1), timeout: 5000, …}”）
    if(userStore.token){
        config.headers.token = userStore.token; // 注：此处通过修改配置对象中的“headers”属性，向请求头中添加了一个名为“token”的字段（现在携带的是用户登录成功后服务器返回的token）
    }
    return config; // 注1：如果此处不返回配置对象，则后续发请求时，请求将不会被发出（即请求会被中断）
    // 注2：在配置对象“config”中，有一个属性叫“headers”，它是一个对象，里面可以存放“请求头信息”。“请求头”经常被用于在向服务器发送请求时携带“公共参数”（这个公共参数一般是token）↑
});
//响应拦截器（注：它接收两个参数，它们分别是“响应成功时”和“响应失败（即出错）时”执行的回调函数，响应成功时回调函数中会被注入服务器返回的数据——“response”作为参数，出错时回调函数中会被注入错误对象——“error”作为参数）
request.interceptors.response.use((response) => {
    console.log(response) // 注：此处打印出来的“response”对象是一个响应对象（它包含了服务器返回的详细信息）（控制台中输出“{data: {…}, status: 200, statusText: 'OK', headers: {…}, config: {…}, request: XMLHttpRequest}”）
    // 处理响应数据（注：此处直接返回“response.data”，“request.ts”文件的外部（也就是“vue组件”）通过它拿到服务器返回的数据，以达到“简化代码”的目的）↓
    return response.data;
}, (error) => {
    //出错时执行的回调函数（一般被用于处理http网络错误）
    let message = ''; // 定义一个变量，这个变量被用于存储提示信息
    console.log(error) // AxiosError {message: 'timeout of 5000ms exceeded', name: 'AxiosError', code: 'ECONNABORTED', config: {…}, request: XMLHttpRequest, …}（注：其中有request字段，但是没有response字段）
    console.log(error.response) // undefined
    if (error.response) {
        // 获取“http状态码”↓
        let status = error.response.status;
        switch (status) {
            case 401:
                message = "token过期";
                break;
            case 403:
                message = '无权访问';
                break;
            case 404:
                message = "请求地址错误";
                break;
            case 500:
                message = "服务器出现问题";
                break;
            default:
                message = "无网络";
        }
    }  else {
        message = "请求失败，无响应数据返回";
    }
    // 弹出消息提示框，显示错误信息↓
    ElMessage({
        type: 'error',
        // message: message
        message // 注：此处使用了ES6的“属性名简写”语法
    })
    // 返回Promise对象，终结“Promise链”，并传入错误信息对象↓
    /* 注：在此处，文心快码解释了“终结Promise链”的含义：
       1. Promise链的基本概念：在JavaScript中，Promise是一个用于异步编程的对象，它表示一个最终可能完成（fulfilled）或失败（rejected）的异步操作及其结果值。Promise链是通过.then()和.catch()方法将多个Promise对象串联起来，形成的一种链式调用结构。在Promise链中，每个.then()或.catch()方法都会返回一个新的Promise对象，从而允许后续的异步操作继续以链式的方式执行。
       2. 终结Promise链的含义：“终结Promise链”通常指的是在Promise链的某个环节，通过显式地返回一个已经被拒绝（rejected）的Promise对象来中断链的后续执行。这通常用于处理错误或异常情况，确保链中的后续.then()方法不会被调用，而是直接跳转到链中第一个.catch()方法（如果有的话）或链外的错误处理逻辑。在当前代码中，在响应拦截器的“错误处理回调函数”中，代码“return Promise.reject(error);”被用作“终结Promise链”。
       在这行代码中，“Promise.reject(error)”是一个静态方法，它被用于创建一个被拒绝的Promise对象，并将“error”作为“拒绝的原因”传递给后续的.catch()方法。通过返回这个被拒绝的Promise对象（即代码“return Promise.reject(error);”），我们终结了当前的Promise链。这意味着链中后续的.then()方法将不会被调用，而是会跳转到链中第一个.catch()方法（或链外的错误处理逻辑）来处理这个错误。
       3.总结：“终结Promise链”是异步编程中处理错误的一种常见做法，它通过使用Promise.reject()来中断链的后续执行，并将错误传递给链中的错误处理逻辑。在提供的代码片段中，响应拦截器的错误处理回调函数通过返回Promise.reject(error)来终结Promise链，并传递错误信息。↓ */
    return Promise.reject(error);
});
console.log(axios)
// 注：此处打印出来的“axios”对象，它是一个函数↓，在被调用时，它会返回一个新的函数↓
/* ƒ wrap() {
    return fn.apply(thisArg, arguments);
  }↑ */
console.log(request)
// 注：此处打印出来的“request”对象，它也是一个函数↓，在被调用时，它会返回一个新的函数↓
/* ƒ wrap() {
    return fn.apply(thisArg, arguments);
  }↑ */
//第三步：将封装后的axios实例对象导出，以供外部使用（注：虽然都是“axios”，但是因为相较于原始的“axios”而言，被封装后的“axios实例对象”（即“request”）带有额外的配置，所以在此处被导出的内容应该是它）↓
export default request;